<template>
	<canvas :style="canvasStyle" :canvas-id="canvasId" :id="canvasId"></canvas>
</template>
<script>
	export default {
		name: "p-canvas",
		props: {
			canvasId: {
				type: String,
				default: 'canvas_pe',
			},
			unit: {
				type: String,
				default: 'px',
			},
			options: Array,
			width: {
				type: [String, Number]
			},
			height: {
				type: [String, Number]
			},

		},
		data() {
			return {
				color: ''
			};
		},
		computed: {
			canvasStyle() {
				const {
					width,
					height,
				} = this, {
					unit
				} = this
				const w = unit === 'px' ? width || uni.upx2px(750) : (uni.upx2px(width || 750))
				const h = unit === 'px' ? height || uni.upx2px(750) : (uni.upx2px(height || 750))
				return `width:${w}px;height:${h}px`
			},
		},
		watch: {
			options: {
				handler(val) {
					this.init()
				},
				deep: true
			}
		},
		async mounted() {
			this.init()
		},
		methods: {
			getImageUrl(url) {
				if (url.slice(0, 4) !== 'http') return Promise.resolve(url)
				return new Promise((resolve, reject) => {
					uni.downloadFile({
						url,
						success: (r) => {
							resolve(r.tempFilePath)
						},
						fail(f) {
							console.error(JSON.stringify(f));
							reject('')
						}

					})
				})
			},
			async init() {
				const {
					canvasId,
					options
				} = this
				const ctx = uni.createCanvasContext(canvasId, this);
				this.ctx = ctx
				if (options.fillStyle) ctx.fillStyle = options.fillStyle;
				if (options.strokeStyle) ctx.strokeStyle = options.strokeStyle;
				const list = await this.handleList(this.options)
				list.forEach(item => {
					this.handleCanvas(item)
				})
				this.isOk = true
				this.ctx.draw()
			},
			handleList(list) {
				// 'blur',
				const useUnit = ['x', 'y', 'w', 'h', 'sw', 'sh', 'mx', 'r', 'fontSize', 'lineHeight']
				return new Promise(async (resolve) => {
					const newList = JSON.parse(JSON.stringify(list))
					for (const item of newList) {
						if (this.unit === 'rpx') {
							for (let key in item) {
								if (useUnit.includes(key)) {
									item[key] = uni.upx2px(item[key])
								}
							}
						}
						if (item.url) {
							const [url, f] = await this.getImageUrl(item.url).then(r => [r, null], f => [null,
								f
							])
							item.url = url || f
						}
						if (item.children && item.children.length) {
							item.children = await this.handleList(item.children)
						}
					}
					resolve(newList)
				})
			},
			handleCanvas(i, content) {
				const {
					ctx
				} = this
				let item = JSON.parse(JSON.stringify(i))
				if (content) {
					item.x = content.x + i.x
					item.y = content.y + i.y
				}
				ctx.save()
				if (item.shadow) {
					this.handleShadow(item.shadow)
				} else {
					ctx.setShadow(0, 0, 0, 'transparent')
				}

				if (item.shape === 'arc') {
					this.handleArc(item, content)
				}
				if (item.shape === 'line') {
					this.handleLine(item, content)
				}
				if (item.shape === 'image') {
					this.handleImage(item, content)
				}
				if (item.shape === 'text') {
					this.handleText(item, content)
				}
				if (item.shape === 'rect') {
					this.handleRect(item, content)
				}
				if (item.fillGradient) {
					this.handleGradient(item.fillGradient)
				} else if (item.fill) {
					ctx.setFillStyle(item.fill)
					ctx.fill();
				}
				if (item.stroke) {
					ctx.setStrokeStyle(item.stroke);
					ctx.stroke();
				}
				if (item.shape !== 'image' && item.url) {
					ctx.clip()
					const params = {
						shape: 'image',
						url: item.url,
						x: 0,
						y: 0,
						w: item.w,
						h: item.h,
					}
					if (item.shape === 'arc') {
						params.w = 2 * item.r
						params.h = 2 * item.r
					}
					this.handleCanvas(params, item)
				}
				if (item.children && item.children.length) {
					ctx.clip()
					item.children.forEach(itm => {
						this.handleCanvas(itm, item)
					})
				}
				ctx.restore()
			},
			handleArc(item, content) {
				const {
					ctx
				} = this
				const {
					x,
					y,
					r,
					stroke,
					fill,
					children
				} = item
				ctx.beginPath()
				ctx.arc(x + r, y + r, r, 0, 2 * Math.PI)
				ctx.closePath();
			},
			handleImage(item, content) {
				const {
					ctx
				} = this
				const {
					x,
					y,
					url,
					w,
					h,
					sx,
					sy,
					sw,
					sh,
					children
				} = item
				const list = this.removeUndefind([url, x, y, w, h, sx, sy, sw, sh])
				ctx.drawImage(...list);
			},
			handleRect(item, content) {
				const {
					ctx
				} = this
				const {
					x,
					y,
					w,
					h,
					r,
					stroke,
					url
				} = item
				const list = this.removeUndefind([x, y, w, h])
				ctx.beginPath()
				if (r) {
					ctx.moveTo(x + r, y);
					ctx.arcTo(x + w, y, x + w, y + h, r);
					ctx.arcTo(x + w, y + h, x, y + h, r);
					ctx.arcTo(x, y + h, x, y, r);
					ctx.arcTo(x, y, x + w, y, r);
				} else {
					ctx.rect(...list)
				}

				ctx.closePath();

			},
			handleText(item, content) {
				const {
					ctx
				} = this
				const {
					x,
					y,
					w,
					mx,
					rows,
					font,
					color,
					fontSize,
					line,
					lineHeight,
					lineColor,
				} = item
				let text = item.text
				let oldText = item.text
				const sliceText = (rows) => {
					const t = text + oldText[0]
					let t_ = t
					if (rows === 1) {
						t_ += '...'
					}
					if (ctx.measureText(t_).width > w) {
						const test = /^[a-zA-Z]*$/
						if(test.test(text[text.length-1])){
							const textSplit = text.split(' ')
							if(textSplit.length > 1){
								oldText=textSplit.splice(textSplit.length-1,1)+oldText
								text = textSplit.join(' ')
							}
						}	
						
						if (rows === 1) {
							text = text + '...'
							oldText = ''
						}
						return oldText

					} else {
						text = t
						oldText = oldText.slice(1)
						return sliceText(rows)
					}
				}
				if (w && w < ctx.measureText(text).width && rows !== 0) {
					text = ''
					item.rows--
					this.handleText({
						...item,
						y: y + (lineHeight || (fontSize && fontSize + 10) || 20),
						text: sliceText(rows)
					}, content)
				}
				const list = this.removeUndefind([text, x, y, mx])
				ctx.setTextBaseline('top')
				if (font) {
					ctx.font = font
				} else if (fontSize) {
					ctx.setFontSize(fontSize)
				}
				if (color) {
					ctx.setFillStyle(color)
				}
				if (line) {
					this.handleCanvas({
						shape: 'line',
						x,
						y: y + (lineHeight || fontSize || 20),
						w: ctx.measureText(text).width,
						stroke: line || color,
					})
				}
				ctx.fillText(...list);
			},
			handleLine(item, content) {
				const {
					ctx
				} = this
				const {
					x = 0,
						y = 0,
						w = 100,
						h = 1,
				} = item
				ctx.beginPath()
				ctx.moveTo(x, y)
				ctx.lineTo(w + x, y)
				ctx.closePath()
				ctx.lineWidth = h

			},
			handleGradient(gradient) {
				const {
					ctx
				} = this
				const {
					x0 = 0, y0 = 0, x1 = 0, y1 = 0, color0 = "#C9964B", color1 = "#e987ff"
				} = gradient
				const grd = ctx.createLinearGradient(x0, y0, x1, y1, )
				grd.addColorStop(0, color0)
				grd.addColorStop(1, color1)
				// Fill with gradient
				ctx.setFillStyle(grd)
				ctx.fill()
			},
			handleShadow(shadow) {
				if (shadow && shadow.length) {
					console.log(shadow);
					this.ctx.setShadow(...shadow)
					return
				}
				const {
					ctx
				} = this
				const {
					x,
					y,
					blur,
					color
				} = shadow
				ctx.shadowOffsetX = x
				ctx.shadowOffsetY = y
				ctx.shadowColor = color
				ctx.shadowBlur = blur
			},

			removeUndefind(list) {
				list.some((item, index) => {
					const bool = typeof item === 'number' || index === 0
					if (!bool) {
						list.length = index
					}
					return !bool
				})
				return list
			},
			getCanvasUrl(params = {}) {
				if (!this.isOk) {
					const title = 'canvas未渲染成功~，请稍后在试'
					uni.showToast({
						title,
						icon: 'none'
					})
					return Promise.reject(title)
				}
				uni.showLoading({
					mask: true
				})
				return new Promise((resolve, reject) => {
					uni.canvasToTempFilePath({
						canvasId: this.canvasId,
						quality: 1, //图片质量
						fileType: 'png',
						success: (res) => {
							resolve(res.tempFilePath)
						},
						fail(r) {
							reject(r)
						},
						complete() {
							uni.hideLoading()
						},
						...params,
					}, this);
				})
			}
		}
	}
</script>